home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1997 #1
/
Amiga Plus CD - 1997 - No. 01.iso
/
pd
/
programmierung
/
oberonv4
/
demos
/
rott.mod
(
.txt
)
< prev
next >
Wrap
Oberon Text
|
1990-01-01
|
10KB
|
241 lines
Syntax10.Scn.Fnt
Syntax10i.Scn.Fnt
MODULE Rott; (* bh '90; V2.2 shml 22 Mar 93 *)
IMPORT Oberon, Display, Display1, Texts, MenuViewers, Viewers, TextFrames, Input, Math;
CONST P = 4; Q = 1; G = 0.001; F = 0.00000001; invert = Display.invert; delay = 50; (* ms *)
TYPE
Frame = POINTER TO FrameDesc;
FrameDesc = RECORD(Display.FrameDesc);
a, b, da, db: REAL;
n, t: LONGINT
END;
StepMsg = RECORD(Display.FrameMsg) END;
W: Texts.Writer;
T: Oberon.Task;
PROCEDURE Line(F: Display.Frame; col, X0, Y0, X1, Y1, mode: INTEGER);
(* Draws a line from (X0, Y0) to (X1, Y1) inclusive, clipped against F. For all line points (x, y) the following holds
always: (min(X0, X1) <= x) & (x <= max(X0, X1) & (min(Y0, Y0) <= y) & (y <= max(Y0, Y1). *)
VAR x, y, dx, dy, d, inc, L, B, R, T, Xmin, Xmax, Ymin, Ymax: INTEGER;
BEGIN
L := F.X; B := F.Y; R := F.X + F.W; T := F.Y + F.H;
IF X0 < X1 THEN Xmin := X0; Xmax := X1 ELSE Xmin := X1; Xmax := X0 END;
IF Y0 < Y1 THEN Ymin := Y0; Ymax := Y1 ELSE Ymin := Y1; Ymax := Y0 END;
IF (L <= Xmax) & (Xmin < R) & (B <= Ymax) & (Ymin < T) THEN (* line may be visible *)
IF Xmin = Xmax THEN Display.ReplConstC(F, col, Xmin, Ymin, 1, Ymax-Ymin+1, mode)
ELSIF Ymin = Ymax THEN Display.ReplConstC(F, col, Xmin, Ymin, Xmax-Xmin+1, 1, mode)
ELSE
IF (Y1-Y0) < (X0-X1) THEN x := X0; X0 := X1; X1 := x; y := Y0; Y0 := Y1; Y1 := y END;
dx := 2*(X1-X0); dy := 2*(Y1-Y0); x := X0; y := Y0; inc := 1;
IF (L <= Xmin) & (Xmax < R) & (B <= Ymin) & (Ymax < T) THEN (* no clipping *)
IF dy > dx THEN d := dy DIV 2;
IF dx < 0 THEN inc := -1; dx := -dx END;
WHILE y <= Y1 DO
Display.Dot(col, x, y, mode);
INC(y); DEC(d, dx);
IF d < 0 THEN INC(d, dy); INC(x, inc) END
END
ELSE d := dx DIV 2;
IF dy < 0 THEN inc := -1; dy := -dy END;
WHILE x <= X1 DO
Display.Dot(col, x, y, mode);
INC(x); DEC(d, dy);
IF d < 0 THEN INC(d, dx); INC(y, inc) END
END
END
ELSE (* dot-wise clipping *)
IF dy > dx THEN d := dy DIV 2;
IF dx < 0 THEN inc := -1; dx := -dx END;
WHILE y <= Y1 DO
IF (L <= x) & (x < R) & (B <= y) & (y < T) THEN Display.Dot(col, x, y, mode) END;
INC(y); DEC(d, dx);
IF d < 0 THEN INC(d, dy); INC(x, inc) END
END
ELSE d := dx DIV 2;
IF dy < 0 THEN inc := -1; dy := -dy END;
WHILE x <= X1 DO
IF (L <= x) & (x < R) & (B <= y) & (y < T) THEN Display.Dot(col, x, y, mode) END;
INC(x); DEC(d, dy);
IF d < 0 THEN INC(d, dx); INC(y, inc) END
END
END
END
END
END
END Line;
PROCEDURE Circle(F: Display.Frame; col, X, Y, R, mode: INTEGER);
(* Draws a circle with center (X, Y) and radius R, clipped against F. For all circle points (x, y) the following holds always:
(X-R <= x) & (x < X+R) & (Y-R <= y) & (y < Y+R). *)
VAR x, y, dx, dy, d, L, B, Rt, T: INTEGER;
PROCEDURE Dot4 (x1, x2, y1, y2: INTEGER);
BEGIN
Display.Dot(col, x1, y1, mode);
Display.Dot(col, x1, y2, mode);
Display.Dot(col, x2, y1, mode);
Display.Dot(col, x2, y2, mode)
END Dot4;
PROCEDURE Dot4c (x1, x2, y1, y2: INTEGER);
BEGIN
IF (L <= x1) & (x1 < Rt) THEN
IF (B <= y1) & (y1 < T) THEN Display.Dot(col, x1, y1, mode) END;
IF (B <= y2) & (y2 < T) THEN Display.Dot(col, x1, y2, mode) END;
END;
IF (L <= x2) & (x2 < Rt) THEN
IF (B <= y1) & (y1 < T) THEN Display.Dot(col, x2, y1, mode) END;
IF (B <= y2) & (y2 < T) THEN Display.Dot(col, x2, y2, mode) END;
END
END Dot4c;
BEGIN
L := F.X; B := F.Y; Rt := F.X + F.W; T := F.Y + F.H;
IF (L < X+R) & (X-R < Rt) & (B < Y+R) & (Y-R < T) THEN (* circle may be visible *)
x := R-1; y := 0; dx := 8*(x-1); dy := 8*y+4; d := 3 - 4*R;
IF (L <= X-R) & (X+R <= Rt) & (B <= Y-R) & (Y+R <= T) THEN (* no clipping *)
WHILE x > y DO
Dot4(X-x-1, X+x, Y-y-1, Y+y);
Dot4(X-y-1, X+y, Y-x-1, Y+x);
INC(d, dy); INC(dy, 8); INC(y);
IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x) END
END;
IF x = y THEN Dot4(X-x-1, X+x, Y-y-1, Y+y) END
ELSE (* dot-wise clipping *)
WHILE x > y DO
Dot4c(X-x-1, X+x, Y-y-1, Y+y);
Dot4c(X-y-1, X+y, Y-x-1, Y+x);
INC(d, dy); INC(dy, 8); INC(y);
IF d >= 0 THEN DEC(d, dx); DEC(dx, 8); DEC(x) END
END;
IF x = y THEN Dot4c(X-x-1, X+x, Y-y-1, Y+y) END
END
END
END Circle;
PROCEDURE Draw(F: Frame);
CONST c1 = 1; c2 = 3; c3 = 15;
VAR xla, yla, xha, yha, xhb, yhb, xda, yda, xdb, ydb, x0, y0: INTEGER; l ,d, h, r: REAL;
BEGIN
x0 := F.X + F.W DIV 2; y0 := F.Y + F.H DIV 2;
IF F.W > F.H THEN l := F.H ELSE l := F.W END;
l := l / 6; h := 1.558 * l; d := l / 8;
r := Math.cos(F.a);
xla := SHORT(ENTIER(l * r + 0.5));
xha := SHORT(ENTIER(h * r + 0.5));
xda := SHORT(ENTIER(d * r + 0.5));
r := Math.sin(F.a);
yla := SHORT(ENTIER(l * r + 0.5));
yha := SHORT(ENTIER(h * r + 0.5));
yda := SHORT(ENTIER(d * r + 0.5));
r := Math.cos(F.b);
xhb := SHORT(ENTIER(h * r + 0.5));
xdb := SHORT(ENTIER(d * r + 0.5));
r := Math.sin(F.b);
yhb := SHORT(ENTIER(h * r + 0.5));
ydb := SHORT(ENTIER(d * r + 0.5));
Display1.Line(F, c1, x0-xla-xda-yda, y0-yla-yda+xda, x0+xla+xda-yda, y0+yla+yda+xda, invert);
Display1.Line(F, c1, x0-xla-xda+yda, y0-yla-yda-xda, x0+xla-xda+yda, y0+yla-yda-xda, invert);
Display1.Line(F, c1, x0-xla-xda-yda, y0-yla-yda+xda, x0-xla-xda+yda, y0-yla-yda-xda, invert);
Display1.Line(F, c1, x0+xla+xda-yda, y0+yla+yda+xda, x0+xla+xda+yha, y0+yla+yda-xha, invert);
Display1.Line(F, c1, x0+xla-xda+yda, y0+yla-yda-xda, x0+xla-xda+yha, y0+yla-yda-xha, invert);
Display1.Line(F, c1, x0+xla+xda+yha, y0+yla+yda-xha, x0+xla-xda+yha, y0+yla-yda-xha, invert);
Display1.Line(F, c2, x0-xla+xdb-ydb, y0-yla+ydb+xdb, x0-xla+xdb+yhb, y0-yla+ydb-xhb, invert);
Display1.Line(F, c2, x0-xla-xdb-ydb, y0-yla-ydb+xdb, x0-xla-xdb+yhb, y0-yla-ydb-xhb, invert);
Display1.Line(F, c2, x0-xla+xdb-ydb, y0-yla+ydb+xdb, x0-xla-xdb-ydb, y0-yla-ydb+xdb, invert);
Display1.Line(F, c2, x0-xla+xdb+yhb, y0-yla+ydb-xhb, x0-xla-xdb+yhb, y0-yla-ydb-xhb, invert);
Display1.Circle(F, c3, x0-xla, y0-yla, SHORT(ENTIER(d)), invert);
Display1.Circle(F, c3, x0, y0, SHORT(ENTIER(d)), invert);
END Draw;
PROCEDURE Der(a, b, da, db: REAL; VAR Da, Db, Dda, Ddb: REAL);
VAR x, y, det, sind, cosd, f: REAL;
BEGIN
Da := da; Db := db;
sind := Math.sin(a - b);
cosd := Math.cos(a - b);
x := G * Math.sin(a) - db * db * cosd;
y := G * Math.sin(b) + da * da * cosd;
det := P * Q - sind * sind;
IF da > 10*F THEN f := F ELSIF da < -10*F THEN f := -F ELSE f := 0 END;
Dda := (sind * y - Q * x) / det - f;
IF db > 10*F THEN f := F ELSIF db < -10*F THEN f := -F ELSE f := 0 END;
Ddb := (sind * x - P * y) / det - f
END Der;
PROCEDURE Step(F: Frame);
VAR dda1, ddb1, dda2, ddb2, dda3, ddb3, dda4, ddb4, da1, db1, da2, db2, da3, db3, da4, db4: REAL;
BEGIN
Der(F.a, F.b, F.da, F.db, da1, db1, dda1, ddb1);
Der(F.a+3*da1, F.b+3*db1, F.da+3*dda1, F.db+3*ddb1, da2, db2, dda2, ddb2);
Der(F.a+3*da2, F.b+3*db2, F.da+3*dda2, F.db+3*ddb2, da3, db3, dda3, ddb3);
Der(F.a+6*da3, F.b+6*db3, F.da+6*dda3, F.db+6*ddb3, da4, db4, dda4, ddb4);
Draw(F);
F.a := F.a + da1 + 2 * da2 + 2 * da3 + da4;
F.b := F.b + db1 + 2 * db2 + 2 * db3 + db4;
F.da := F.da + dda1 + 2 * dda2 + 2 * dda3 + dda4;
F.db := F.db + ddb1 + 2 * ddb2 + 2 * ddb3 + ddb4;
Draw(F);
INC(F.n)
END Step;
PROCEDURE Edit(F: Frame; X, Y: INTEGER; Keys: SET);
VAR x0, y0: INTEGER;
BEGIN
IF 2 IN Keys THEN
F.da := 0; F.db := 0; x0 := X; y0 := Y;
REPEAT
Input.Mouse(Keys, X, Y);
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y);
IF (X # x0) OR (Y # y0) THEN
Draw(F);
F.a := F.a + (Y - y0) / 100; F.b := F.b + (X - x0) / 100;
Draw(F);
x0 := X; y0 := Y
END
UNTIL Keys = {};
ELSE
REPEAT
Input.Mouse(Keys, X, Y);
Oberon.DrawCursor(Oberon.Mouse, Oberon.Arrow, X, Y);
UNTIL Keys = {}
END
END Edit;
PROCEDURE* Handle(F: Display.Frame; VAR M: Display.FrameMsg);
VAR F1: Frame;
BEGIN
WITH F: Frame DO
IF M IS Oberon.InputMsg THEN
WITH M: Oberon.InputMsg DO
IF M.id = Oberon.track THEN Edit(F, M.X, M.Y, M.keys) END
END
ELSIF M IS MenuViewers.ModifyMsg THEN
WITH M: MenuViewers.ModifyMsg DO
IF M.id = MenuViewers.extend THEN F.H := F.H + F.Y - M.Y + M.dY
ELSIF M.id = MenuViewers.reduce THEN F.H := F.H + F.Y - M.Y - M.dY
END;
F.Y := M.Y;
Display.ReplConst(0, F.X, F.Y, F.W, F.H, Display.replace);
Draw(F)
END
ELSIF M IS Oberon.CopyMsg THEN NEW(F1); F1^ := F^; M(Oberon.CopyMsg).F := F1
ELSIF M IS StepMsg THEN Step(F)
END
END
END Handle;
PROCEDURE Open*;
VAR F: Frame; x, y: INTEGER; v: MenuViewers.Viewer;
BEGIN
NEW(F); F.a := Math.pi; F.b := 3.14; F.da := 0.0; F.db := 0.0; F.n := 0; F.t := 0; F.handle := Handle;
Oberon.AllocateUserViewer(Oberon.Par.vwr.X, x, y);
v := MenuViewers.New(
TextFrames.NewMenu("Rott.Open ", " System.Close System.Copy System.Grow"),
F, TextFrames.menuH, x, y)
END Open;
PROCEDURE Start*;
BEGIN Oberon.Install(T)
END Start;
PROCEDURE Stop*;
BEGIN Oberon.Remove(T);
END Stop;
PROCEDURE* Handler;
VAR m: StepMsg;
BEGIN Viewers.Broadcast(m); T.time := Input.Time() + Input.TimeUnit * delay DIV 1000
END Handler;
BEGIN Texts.OpenWriter(W); NEW(T); T.handle := Handler; T.time := 0; Start
END Rott.
Rott.Open
Rott.Start
Rott.Stop